home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / xvisrc.zip / TAGS.C < prev    next >
C/C++ Source or Header  |  1992-07-28  |  7KB  |  321 lines

  1. /* Copyright (c) 1990,1991,1992 Chris and John Downey */
  2. #ifndef lint
  3. static char *sccsid = "@(#)tags.c    2.1 (Chris & John Downey) 7/29/92";
  4. #endif
  5.  
  6. /***
  7.  
  8. * program name:
  9.     xvi
  10. * function:
  11.     PD version of UNIX "vi" editor, with extensions.
  12. * module name:
  13.     tags.c
  14. * module function:
  15.     Handle tags.
  16. * history:
  17.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  18.     Originally by Tim Thompson (twitch!tjt)
  19.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  20.     Heavily modified by Chris & John Downey
  21.  
  22. ***/
  23.  
  24. #include "xvi.h"
  25.  
  26. #define    LSIZE        512    /* max. size of a line in the tags file */
  27.  
  28. /*
  29.  * Macro evaluates true if char 'c' is a valid identifier character.
  30.  * Used by tagword().
  31.  */
  32. #define IDCHAR(c)    (is_alnum(c) || (c) == '_')
  33.  
  34. /*
  35.  * Return values for find_tag().
  36.  */
  37. #define    FT_SUCCESS    0        /* found tag */
  38. #define    FT_CANT_OPEN    1        /* can't open given file */
  39. #define    FT_NO_MATCH    2        /* no such tag in file */
  40. #define    FT_ERROR    3        /* error in tags file */
  41.  
  42. static    int    find_tag P((char *, char *, char **, char **));
  43.  
  44. /*
  45.  * Tag to the word under the cursor.
  46.  */
  47. void
  48. tagword()
  49. {
  50.     char    ch;
  51.     Posn    pos;
  52.     char    tagbuf[50];
  53.     char    *tp = tagbuf;
  54.  
  55.     pos = *curwin->w_cursor;
  56.  
  57.     ch = gchar(&pos);
  58.     if (!IDCHAR(ch))
  59.     return;
  60.  
  61.     /*
  62.      * Now grab the chars in the identifier.
  63.      */
  64.     while (IDCHAR(ch) && tp < tagbuf + sizeof(tagbuf)) {
  65.     *tp++ = ch;
  66.     if (inc(&pos) != mv_SAMELINE)
  67.         break;
  68.     ch = gchar(&pos);
  69.     }
  70.  
  71.     /*
  72.      * If the identifier is too long, just beep.
  73.      */
  74.     if (tp >= tagbuf + sizeof(tagbuf)) {
  75.     beep(curwin);
  76.     return;
  77.     }
  78.  
  79.     *tp = '\0';
  80.  
  81.     (void) do_tag(curwin, tagbuf, FALSE, TRUE, TRUE);
  82. }
  83.  
  84. /*
  85.  * do_tag(window, tag, force, interactive) - goto tag
  86.  */
  87. bool_t
  88. do_tag(window, tag, force, interactive, split)
  89. Xviwin    *window;
  90. char    *tag;            /* function to search for */
  91. bool_t    force;            /* if true, force re-edit */
  92. bool_t    interactive;        /* true if reading from tty */
  93. bool_t    split;            /* true if want to split */
  94. {
  95.     char    *fname;        /* file name to edit (2nd field) */
  96.     char    *field3;    /* 3rd field - pattern or line number */
  97.     bool_t    edited;        /* TRUE if we have edited the file */
  98.     Xviwin    *tagwindow;    /* tmp window pointer */
  99.     int        status;        /* return value from find_tag() */
  100.     int        count;
  101.     char    **tagfiles;
  102.  
  103.     if (tag == NULL || tag[0] == '\0') {
  104.     if (interactive) {
  105.         show_error(window, "Usage: :tag <identifier>");
  106.     } else {
  107.         beep(window);
  108.     }
  109.     return(FALSE);
  110.     }
  111.  
  112.     tagfiles = Pl(P_tags);
  113.     if (tagfiles == NULL || tagfiles[0] == NULL) {
  114.     if (interactive) {
  115.         show_error(window, "No tags parameter set!");
  116.         return(FALSE);
  117.     }
  118.     }
  119.  
  120.     gotocmd(window, FALSE);
  121.  
  122.     for (count = 0; tagfiles[count] != NULL; count++) {
  123.     status = find_tag(tag, tagfiles[count], &fname, &field3);
  124.     if (status == FT_SUCCESS) {
  125.         break;
  126.     }
  127.     }
  128.  
  129.     /*
  130.      * Either:
  131.      *    we have found the tag in tagfiles[count]
  132.      * or:
  133.      *    we have failed to find it, and tagfiles[count - 1]
  134.      *    contains the name of the last tags file tried.
  135.      */
  136.  
  137.     switch (status) {
  138.     case FT_CANT_OPEN:
  139.     if (interactive) {
  140.         show_error(window, "Can't open tags file \"%s\"",
  141.                 tagfiles[count - 1]);
  142.     }
  143.     return(FALSE);
  144.  
  145.     case FT_ERROR:
  146.     if (interactive) {
  147.         show_error(window, "Format error in tags file \"%s\"",
  148.                 tagfiles[count - 1]);
  149.     }
  150.     return(FALSE);
  151.  
  152.     case FT_NO_MATCH:
  153.     if (interactive) {
  154.         show_error(window, "Tag not found");
  155.     }
  156.     return(FALSE);
  157.     }
  158.  
  159.     /*
  160.      * If we are already editing the file, just do the search.
  161.      *
  162.      * If "autosplit" is set, create a new buffer window and
  163.      * edit the file in it.
  164.      *
  165.      * Else just edit it in the current window.
  166.      */
  167.     tagwindow = find_window(window, fname);
  168.     if (tagwindow != NULL) {
  169.     curwin = tagwindow;
  170.     curbuf = curwin->w_buffer;
  171.     edited = TRUE;
  172.  
  173.     } else if (split && can_split() && do_buffer(window, fname)) {
  174.     edited = TRUE;
  175.  
  176.     } else if (do_edit(window, force, fname)) {
  177.     edited = TRUE;
  178.  
  179.     } else {
  180.     /*
  181.      * If the re-edit failed, abort here.
  182.      */
  183.     edited = FALSE;
  184.     }
  185.  
  186.     /*
  187.      * Finally, search for the given pattern in the file,
  188.      * but only if we successfully edited it. Note that we
  189.      * always use curwin at this stage because it is not
  190.      * necessarily the same as our "window" parameter.
  191.      */
  192.     if (edited) {
  193.     char    *cp;
  194.  
  195.     /*
  196.      * Remove trailing newline if present.
  197.      */
  198.     cp = field3 + strlen(field3) - 1;
  199.     if (*cp == '\n') {
  200.         *cp-- = '\0';
  201.     }
  202.  
  203.     if (*field3 == '/' || *field3 == '?') {
  204.         int    old_rxtype;
  205.  
  206.         /*
  207.          * Remove leading and trailing '/'s or '?'s
  208.          * from the search pattern.
  209.          */
  210.         field3++;
  211.         if (*cp == '/' || *cp == '?') {
  212.         *cp = '\0';
  213.         }
  214.  
  215.         /*
  216.          * Set the regular expression type to rt_TAGS
  217.          * so that only ^ and $ have a special meaning;
  218.          * this is like nomagic in "real" vi.
  219.          */
  220.         old_rxtype = Pn(P_regextype);
  221.         set_param(P_regextype, rt_TAGS, (char **) NULL);
  222.  
  223.         if (dosearch(curwin, field3, '/')) {
  224.         show_file_info(curwin);
  225.         } else {
  226.         beep(curwin);
  227.         }
  228.         set_param(P_regextype, old_rxtype, (char **) NULL);
  229.     } else if (is_digit(*field3)) {
  230.         /*
  231.          * Not a search pattern; a line number.
  232.          */
  233.         do_goto(atol(field3));
  234.     } else {
  235.         show_error(curwin, "Ill-formed tag pattern \"%s\"", field3);
  236.     }
  237.     move_window_to_cursor(curwin);
  238.     update_all();
  239.     }
  240.  
  241.     return(TRUE);
  242. }
  243.  
  244. static int
  245. find_tag(tag, file, fnamep, pattern)
  246. char    *tag;
  247. char    *file;
  248. char    **fnamep;
  249. char    **pattern;
  250. {
  251.     register char    *str;        /* used for scanning strings */
  252.     FILE        *tp;        /* file pointer for tags file */
  253.     static char        lbuf[LSIZE];    /* input line from tags file */
  254.     bool_t        found;
  255.     int            max_chars;
  256.  
  257.     max_chars = Pn(P_taglength);
  258.     if (max_chars == 0) {
  259.     max_chars = INT_MAX;
  260.     }
  261.  
  262.     tp = fopen(file, "r");
  263.     if (tp == NULL) {
  264.     return(FT_CANT_OPEN);
  265.     }
  266.  
  267.     found = FALSE;
  268.     while (fgets(lbuf, LSIZE, tp) != NULL) {
  269.     register char    *tagptr;
  270.     register int    nchars;
  271.  
  272.     for (str = lbuf, tagptr = tag, nchars = 0;
  273.         *str == *tagptr && nchars < max_chars;
  274.         str++, tagptr++, nchars++) {
  275.         ;
  276.     }
  277.     if ((*tagptr == '\0' && *str == '\t') || nchars == max_chars) {
  278.         found = TRUE;
  279.         break;
  280.     }
  281.  
  282.     }
  283.  
  284.     (void) fclose(tp);
  285.  
  286.     if (!found) {
  287.     return(FT_NO_MATCH);
  288.     }
  289.  
  290.     /*
  291.      * Okay, we have found the right line.
  292.      * Now extract the second and third fields.
  293.      *
  294.      * If we get here, str points at the tab after the first field,
  295.      * or at part of the tag if we have matched up to taglength.
  296.      * So first move to the start of the second field.
  297.      */
  298.     while (!is_space(*str)) {
  299.     str++;
  300.     }
  301.     while (is_space(*str)) {
  302.     str++;
  303.     }
  304.     *fnamep = str;
  305.  
  306.     /*
  307.      * Find third field and null-terminate second field.
  308.      */
  309.     str = strchr(str, '\t');
  310.     if (str == NULL) {
  311.     (void) fclose(tp);
  312.     return(FT_ERROR);
  313.     }
  314.     while (is_space(*str)) {
  315.     *str++ = '\0';
  316.     }
  317.     *pattern = str;
  318.  
  319.     return(FT_SUCCESS);
  320. }
  321.